<?php
/*
 * Copyright (c) Taras Kudla, 2010
 */
class mod_modules extends gModule {
	
	function init(){
		
	}
	# view module, information about, etc.
	public function view(){
		# getting installed modules
		$installed = $this->api->dbo->select("modules","modname,version,author,installdate");
		$installedarray = $this->api->dbo->select("modules","modname",null,_RESULT_LIST);
		# getting all uninstalled
		$notinstalled = array();
		$dir = $this->api->parseasdir($this->api->get("modsdir"));
		$ddir = opendir($dir);
		chdir($dir);
		while( $item = readdir($ddir)){
			if(is_dir($item) && $item != ".." && $item != "." && !in_array($item, $installedarray) && preg_match("/^[A-z_]+$/", $item))
				$notinstalled [] = $item;
		}
		chdir($this->api->path());
		# getting 3rd party modules
		$dir = $this->api->parseasdir($this->api->get("appmodsdir"));
		$ddir = opendir($dir);
		chdir($dir);
		while( $item = readdir($ddir)){
			if(is_dir($item) && $item != ".." && $item != "." && !in_array($item, $installedarray) && preg_match("/^[A-z_]+$/", $item)){
				$notinstalled [] = $item;
			}
		}
		chdir($this->api->path());
		# sending all information to template
		return $this->api->view->template("modlist",array("installed"=>&$installed,"notinstalled"=>&$notinstalled) );			
	}
	
	public function viewmodule(){
		
		if( !isset($_GET["name"])) return null;
		$module = $this->api->escapeString($_GET["name"]);
		# checking for operations
		if( isset($_GET["install"])) {
			$result=$this->installation($module);
			$message = (!$result)? "m17":"m16";
			if( !$result ){
				$this->remove($module);
			}
	        # trying to set administrator's permissions
	        $hashes = $this->api->dbo->select("functions","hash","where modname='$module'",_RESULT_LIST);
	        $existed = $this->api->dbo->select("groups","access","where id='"._GROUP_ADMIN."'",_RESULT_SINGLE);
	        $existed = explode(",",$existed);
	        foreach($hashes as $k=>$v){
	        	if(!array_key_exists($v,$existed))
	        		array_push($existed,$v);
	        }
			$this->api->dbo->update("groups","set access='".implode(",",$existed)."' where id='"._GROUP_ADMIN."'");
			$this->api->user->resetaccess();			
			return $this->api->message($this->lang->get($message));
		}
		if( isset($_GET["reinstall"])) {
			
			$safe = isset($_GET["safe"]);		
			$result=$this->reinstallation($module,$safe);
			$message = (!$result)? "m19":"m18";
			return $this->api->message($this->lang->get($message));			
		}
		if( isset($_GET["uninstall"])) {
			$result=$this->remove($module);
			$message = (!$result)? "m21":"m20";
			return $this->api->message($this->lang->get($message));			
		}
		$Data = $this->api->dbo->select("modules","installdate,author,version,description,modname","where modname='$module' limit 1 offset 0",_RESULT_ROW);
		if( count($Data)>0){
			$Data["installed"]=true;
		} else {
			# trying to get options.xml file
			$file = $this->api->parseasdir($this->api->get("modsdir")).$module."/options.xml";
			$appmodoptionsfile = $this->api->parseasdir($this->api->get("appmodsdir")).$module."/options.xml";
			if( !file_exists($file)){
				if( !file_exists($appmodoptionsfile)){
				    return $this->api->message($this->lang->get("m14"));
				}
			}
			$options = $this->loadoptions($module);
			if( !$options) {
				return $this->api->message($this->lang->get("m14"));
			}
			$Data["modname"] = $options["module"]["name"];
			$Data["author"]  = $options["module"]["author"];
			$Data["version"] = $options["module"]["version"];
			$Data["description"] = $options["module"]["description"];
			$Data["installed"] = false;	
			$Data["installdate"] = null;			
		}
		return $this->api->view->template("viewmodule",array("data"=>&$Data) );
	}	
	
	# installation by web interface
	public function installation($name=null,$keepdata=false){
        # checking for name or _GET[module]
		if( !is_null($name) ){
			
		} else if ( isset($_GET["module"]) ){
			$name = $this->api->escapeString($_GET["module"]);	
		} else {			
			return false;
		}
		# module object link
        $tmp = null;
        if ($this->api->dbo->select("modules", "*", " where modname='" . $name . "' limit 1",_RESULT_BOOL) )
            return false;
	# parsing options xml file
        $Options = $this->loadoptions($name);
		
        if (!$Options)
            return false;

   	# langterms file
        $this->langterms($name);
        $this->api->dbo->insert("modules", array(
            "modname" => $Options["module"]["name"],
            "author" => $Options["module"]["author"],
            "installdate" => date("Y-m-d H:i:s"),
            "version" => $Options["module"]["version"],
            "description" => $Options["module"]["description"],
            "status"	 =>1
        ));
        $i = 0;
        foreach ($Options["function"] as $k => $v){
            $hash = $this->api->cms->GetHash($Options["module"]["name"], $v["name"]);
            if (is_array($v["level"]))
              {
                foreach ($v["level"] as $q => $e)
                  {
                    if (is_numeric((int) $e))
                      {
                        $this->newlevellink($hash, $e);
                      }
                  }
              }
            else if (is_numeric((int) $v["level"])){
                $this->newlevellink($hash, $v["level"]);

		}
            
            $this->api->dbo->insert("actions", array(
                "hash" => $hash,
                "action" => $v["name"],
                "module" => $Options["module"]["name"],
		"guest" => $v["guest"],
                "runmode" => $v["runmode"],
                "alias" =>  $v["alias"]!=false?$v["alias"]:($Options["module"]["name"] . "-" . strtolower($v["name"])),
                "position" => $v["position"],
                "runwith" => $v["runwith"],
		"onstart" => 0,
            	"withmod"=>"",
            	"weight"  => 0,
            	"comment" => "",
            	"lastsum" => "0",
            	"extime"  => 0,
            	"memuse"  => 0
            ));
          }
		# checking for data keeping
        if ($keepdata == false) {
       	 	# trying to set global environment    
        	$tmpCaller = $this->api->getenvcaller();
        	$tmpLayer  = $this->api->getenvlayer();
        	$newCaller = array("MOD"=>$name,"NAME"=>null,"MESSAGE"=>null,"ERROR"=>null,"ERROR_COUNT"=>0,"CALLSTACK"=>array()); 
        	$this->api->setenvlayer(_ENV_MOD);
        	$this->api->setenvcaller($newCaller);
        	# getting module object
        	$tmp=$this->api->callmodule($name);
        	$tmp->install();
        	$this->api->setenvcaller($tmpCaller);
        	$this->api->setenvlayer($tmpLayer);
        }
        //return true;     
        $this->api->log->write("new module '" . $name . "' installed", _LOG_MESSAGE, _SYS_LOG);
		return true;
	}
	# reinstallation
	public function reinstallation($name,$keepdata=false){
		
		if( !is_null($name) ){
			
		} else if ( isset($_GET["module"]) ){
			$name = $this->api->escapeString($_GET["module"]);	
		} else {			
			return false;
		}
		$this->remove($name,$keepdata);
		$this->installation($name,$keepdata);
		return true;	
	}
	
	# remove module and it's data, $name priority > $_GET
	public function remove($name=null,$keepdata=false){
      
		if( !is_null($name) ){
			
		} else if ( isset($_GET["module"]) ){
			$name = $this->api->escapeString($_GET["module"]);	
		} else {			
			return false;
		}
        if ($keepdata == false)
          {
            $tmp=$this->api->callmodule($name);
            $tmp->uninstall();
          }
        $this->api->dbo->delete("modules", " where modname='$name'");
	# functions deleting
        $this->api->dbo->delete("actions","where module='$name'");
        # global module options deleting  
        $this->api->options->Delete($name);
	# langterms deleting
        $this->api->dbo->delete("langterms", " where term NOT IN (select hash from functions)");
	# levelinks deleting
        $this->api->dbo->delete("levellinks", "where hash NOT IN (select hash from functions) ");
        return true;		
	}	

	/*
	 * Some service functions
	 */

	# new level link
    private function newlevellink($hash, $level)
      {
        $Exists = $this->api->dbo->select("levellinks", "hash", "where hash='" . $hash . "' and level='" . $level . "' limit 1 offset 0", _RESULT_BOOL);
        if (!$Exists)
          {
            $this->api->dbo->insert("levellinks", array(
                "hash" => $hash,
                "level" => $level
            ));
          }
        return true;
      }
	
    # clear all levellinks by hash
    private function eraselevellink($hash){
        $this->api->dbo->delete("levellinks", "where hash='" . $hash . "'");
	
      }	
	
    # module options
    public function loadoptions($name){
        $optionsfile = $this->api->parseasdir($this->api->get("modsdir")).$name."/options.xml";
	$appmodoptionsfile = $this->api->parseasdir($this->api->get("appmodsdir")).$name."/options.xml";
        if (!file_exists($optionsfile)){
           if( !file_exists($appmodoptionsfile)){
               $this->api->error("modules","cannot file configuration for module '$name'");
	       return false;
	   } else {
	       $optionsfile = $appmodoptionsfile;
	   }
        }
        $xml = file_get_contents($optionsfile);
        $xml = @simplexml_load_string($xml);
        if (is_bool($xml) && !$xml){
           $this->core->error("modules","cannot load module configuration '$name' as XML file ");
           return false;
        }
        $data = array();
        # checking for global module data
        if (isset($xml->module) && count($xml->module) == 1 && isset($xml->module->author) && isset($xml->module->version) && isset($xml->module->description))
          {
            $data["module"]["name"] = isset($xml->module->name)?(string)$xml->module->name:$name;
            $data["module"]["author"] = (string)$xml->module->author;
            $data["module"]["version"] = (string)$xml->module->version;
            $data["module"]["description"] = (string)$xml->module->description;
            $data["module"]["tables"] = (isset($xml->module->tables) ? (string)$xml->module->tables : null);
            $data["module"]["updateurl"] = (isset($xml->module->updateurl) ? (string)$xml->module->updateurl : null);
          }
        else
          {
            $this->api->error("modules","module configuration '$name' is not full");
            return false;
          }
        $num = count($xml->function);
        if ($num < 1)
          {
            $this->api->error("modules","there are no functions described in configuration for module '$name'");
            return false;
          }
        foreach ($xml->function as $k => $v)
          {
            if (isset($v->name) && !empty($v->name))
              {         
        		# position detection        
				if( isset($v->position) && !is_numeric((string)$v->position)){
					# checking for system positions
				} else {
					if( !isset($v->position))
						$position=1;
					else 
						$position =(int)$v->position;
				}
				# guest access 
				if( isset($v->guest)){
					$guest=(string)$v->guest;
					$guest=( $guest=="true" || $guest=="1")?1:0;
				} else 
					$guest=0;
				# preparing for data insertion		
                $data["function"][] = array(
                    "name" => (string) $v->name,
                    "runmode" => ((isset($v->runmode) && is_numeric((int) $v->runmode)) ? (int) $v->runmode : 0),
                    "position" => $position,
                    "guest" => $guest,
                    "alias" => ((isset($v->alias)))?trim($v->alias):false,
                    "runwith" => ((isset($v->runwith)) ? (((string) $v->runwith) == "all" ? -1 : 0) : 0),
                    "level" => ((isset($v->level) && !empty($v->level)) ? explode(",", $v->level) : _FUNC_USER)
                );
              }
        }
        /*
         * checking for menu configuration
         */
         if( isset($xml->menu)){
             $data["menu"] = array();
             foreach($xml->menu->item as $k=>$v){
                 if(  (string)$k=="item" ){
                     $attr = $v->attributes();
                     $funcname = (string)$attr["function"];
                     $data["menu"][$funcname] = array();
                 }                 
                 foreach( $v->language as $a=>$b){
                     $attr = $b->attributes();
                     $data["menu"][$funcname]["values"][(string)$attr["name"]]=trim($b);
                 }
                 
                 $data["menu"][$funcname]["parent"]=(isset($v->parent))?trim((string)$v->parent):null;
                 
             }
         }


        return $data;
      }

	# module langterms processing
    private function langterms($mod)
      {
        $file = $this->api->parseasdir($this->api->get("modsdir")). $mod . "/langterms.xml";
	$appmodfile = $this->api->parseasdir($this->api->get("appmodsdir")). $mod . "/langterms.xml";
        if (!file_exists($file)){
            if( !file_exists($appmodfile)){
		return true;
	    } else {
		$file = $appmodfile;
	    }
        }
        $xml = file_get_contents($file);
        $xml = simplexml_load_string($xml);
        if (is_bool($xml) && !$xml)
          {
            $this->api->error("Mod installer","Error in reading langterms xml file ($file)");
            return true;
          }
        $term = $xml->term;
        if (count($term) <= 0)
          {
            return true;
          }
        foreach ($term as $k => $v)
          {
            $parent = 0;
            if (!isset($v->value) || !isset($v->lang) || !isset($v->function))
                continue;
            if (isset($v->parent))
              {
                $q = $this->api->dbo->select("langterms", "id", " where
                       term='" . $this->api->cms->GetHash($mod, trim((string) $v->parent)) . "' and lang='" . trim($v->lang) . "' limit 1 offset 0");
                if (count($q) == 1)
                    $parent = $q[0]["id"];
              }
            $this->api->dbo->insert("langterms", array(
                "term" => $this->api->cms->GetHash($mod, trim((string) $v->function)),
                "lang" => trim($v->lang),
            	"module" => trim($mod),
            	"method" => trim($v->function),
            	"image"=>"",
            	"url"=>"",
                "alias"=>$this->api->cms->getalias($mod,trim((string) $v->function)),
                "value" => $this->api->charset->converttext($this->api->escapeString(trim((string) $v->value))),
                "parent" => $parent
            ));
          }
        return true;
      }
	
	
	/*
	 * General functions, required by interface
	 */
	
	public function install(){
		
	}
	
	public function uninstall(){
		
	}
}